package org.hnzyx.joggle.filter;


import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.hnzyx.joggle.algorithm.RSAUtil;
import org.hnzyx.joggle.cache.CacheOperationManager;
import org.hnzyx.joggle.common.CacheKye;
import org.hnzyx.joggle.common.CommonVariable;
import org.hnzyx.joggle.common.JoggleHttpServletRequestWrapper;
import org.hnzyx.joggle.config.CustomProperties;
import org.hnzyx.joggle.exceptions.NoPermissionException;
import org.hnzyx.joggle.exceptions.SetResponseStatus;
import org.hnzyx.joggle.server.ReplayServer;
import org.hnzyx.joggle.server.SignDetect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.Map;
import java.util.StringJoiner;


public class WebUrlIntercept extends JoggleInterceptor {

    @Autowired
    private SetResponseStatus setResponseStatus;

    @Autowired
    private SignDetect signDetect;

    @Autowired
    private CacheOperationManager cacheOperationManager;

    @Autowired
    private ReplayServer replayServer;

    @Autowired
    private RSAUtil rsaUtil;



    // 检测令牌
    public String checkIsNotNull(HttpServletRequest request) throws NoPermissionException {
        // 没有用户公钥则无权限
        if(StringUtils.isEmpty(request.getHeader(CommonVariable.ACCESS_KEY))){
            throw new NoPermissionException();
        }
        String appSecret = cacheOperationManager.getKey(CacheKye.joggleSecret + request.getHeader(CommonVariable.ACCESS_KEY));
        if(StringUtils.isEmpty(appSecret)){
            throw new NoPermissionException();
        }
        return appSecret;
    }

    // 前置处理
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        long l = System.currentTimeMillis();
        try {
            // 是否免除检测
            String adopt = (String)request.getAttribute(CommonVariable.ADOPT);
            // 获取用户密钥
            String appSecret = this.checkIsNotNull(request);
            // 验证过的请求
            if (adopt != null && adopt != "" && adopt.equalsIgnoreCase(appSecret)) {
                return true;
            }
            // 路径参数解析
            String urlPer = this.urlParameterDecrypt(request, appSecret);
            // 请求体参数解析
            String bodyPer = this.bodyParameterDecrypt(request, appSecret);
            // 签名校验
            signDetect.check(request, request.getRequestURI(), urlPer, bodyPer);
            // 重放检测
            replayServer.check(request);
            // 跳转到正式请求
            System.out.println("检测解密耗时:" + (System.currentTimeMillis() - l));
            return this.dispatcher(request, response,urlPer, bodyPer, appSecret);
        } catch (Exception e){
            setResponseStatus.setStatus(e, response);
            return false;
        }
    }

    // url参数解析
    public String urlParameterDecrypt(HttpServletRequest request, String appSecret) throws Exception {
        StringJoiner pa = new StringJoiner(CommonVariable.JOIN);
        Map<String, String[]> parameterMap =
                request.getParameterMap();
        for (Map.Entry<String, String[]> par : parameterMap.entrySet()){
            if (par.getKey().equals(CommonVariable.PARAMETER)) {
                for (String s : par.getValue()) {
                    pa.add(parameterDecrypt(s, appSecret));
                }
            } else {
                for (String s : par.getValue()) {
                    pa.add(par.getKey() + CommonVariable.EQ + s);
                }
            }
        }
        return pa.toString();
    }

    // 请求体参数解析
    public String bodyParameterDecrypt(HttpServletRequest request, String appSecret) throws Exception {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
            StringBuilder sapd = new StringBuilder();
            reader.lines().forEach(e -> {
                sapd.append(e);
            });
            String mateParameter = null;
            try {
                mateParameter =  rsaUtil.decrypt(sapd.toString().replaceAll(" ","+"),appSecret);
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
            return mateParameter;
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }


    public boolean dispatcher(HttpServletRequest request, HttpServletResponse response, String mateParameter, String bodyParameter, String appSecret) throws ServletException, IOException {
        try {
            // post 重构request
            if (!StringUtils.isEmpty(bodyParameter)){
                JoggleHttpServletRequestWrapper reqWrapper = new JoggleHttpServletRequestWrapper(request);
                reqWrapper.setBody(bodyParameter);
                request = reqWrapper;
            }
            request.setAttribute(CommonVariable.ADOPT, appSecret);
            request.getRequestDispatcher(request.getRequestURI()+ CommonVariable.WHAT + mateParameter).forward(request,response);
        } catch (IOException | ServletException e) {
            e.printStackTrace();
            throw e;
        }
        return false;
    }

    // RSA解密
    public String parameterDecrypt(String parameter, String appSecret) throws Exception {
        // 通过appSecret解密
        try {
            return rsaUtil.decrypt(parameter.replaceAll(" ","+"),appSecret);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

}
